using System;
using System.IO;
using FPLibrary;

namespace GameFrame.Deterministic
{
    internal class LutGenerator
    {
        private const long ATAN_DENSITY1_COVER = 6;
        public const long ATAN_SIZE_DENSITY1 = 393216;
        public const int ATAN_DENSITY2_COVER = 250;
        public const long ATAN_DENSITY2_COVER_RAW = 16384000;
        public const long ATAN_SIZE_DENSITY2 = 3904;
        public const int ATAN_DENSITY3_COVER = 10000;
        public const int ATAN_DENSITY3_COVER_RAW = 655360000;
        public const long ATAN_SIZE_DENSITY3 = 609;
        public const string TABLE_NAME_SIN_COS = "FPSinCos";
        public const string TABLE_NAME_TAN = "FPTan";
        public const string TABLE_NAME_ASIN = "FPAsin";
        public const string TABLE_NAME_ACOS = "FPAcos";
        public const string TABLE_NAME_ATAN = "FPAtan";
        public const string TABLE_NAME_SQRT = "FPSqrt";

        private static void Generate(Func<double, double> op, string file, long min, long max)
        {
            file += ".bytes";
            if (File.Exists(file))
                File.Delete(file);
            using (FileStream fileStream = File.OpenWrite(file))
            {
                for (long index = min; index <= max; ++index)
                {
                    long num = (long) Math.Round(op((double) index / 65536.0) * 65536.0);
                    fileStream.Write(BitConverter.GetBytes(num), 0, 8);
                }
                fileStream.Flush();
            }
        }

        private static void GenerateSqrt(string file)
        {
            file += ".bytes";
            if (File.Exists(file))
                File.Delete(file);
            using (FileStream fileStream = File.OpenWrite(file))
            {
                for (long index = 0; index < 65536L; ++index)
                {
                    byte[] bytes = BitConverter.GetBytes(checked ((int) Math.Round(unchecked (Math.Sqrt(FP.FromRaw(index).AsDouble) * 64.0 * 65536.0))));
                    fileStream.Write(bytes, 0, bytes.Length);
                }
                byte[] bytes1 = BitConverter.GetBytes((int) (FP._1.RawValue << 6));
                fileStream.Write(bytes1, 0, bytes1.Length);
                fileStream.Flush();
            }
        }

        public static void GenerateSinCosPacked(string file)
        {
            file += ".bytes";
            if (File.Exists(file))
                File.Delete(file);
            using (FileStream fileStream = File.OpenWrite(file))
            {
                for (long index = 0; index <= 205887L; ++index)
                {
                    FP fp = FP.FromRaw(index);
                    long num = (long) (uint) checked ((int) FP.FromFloat_UNSAFE(unchecked ((float) Math.Sin(fp.AsDouble))).RawValue) | (long) checked ((int) FP.FromFloat_UNSAFE(unchecked ((float) Math.Cos(fp.AsDouble))).RawValue) << 32 & -4294967296L;
                    fileStream.Write(BitConverter.GetBytes(num), 0, 8);
                }
                for (long index = 1; index <= 205887L; ++index)
                {
                    FP fp1 = FP.FromRaw(index);
                    FP fp2 = FP.FromRaw(205887L - index);
                    long num = (long) (uint) checked ((int) -FP.FromFloat_UNSAFE(unchecked ((float) Math.Sin(fp1.AsDouble))).RawValue) | (long) checked ((int) FP.FromFloat_UNSAFE(unchecked ((float) Math.Cos(fp2.AsDouble))).RawValue) << 32 & -4294967296L;
                    fileStream.Write(BitConverter.GetBytes(num), 0, 8);
                }
            }
        }

        public static void GenerateAtan(string file)
        {
            file += ".bytes";
            if (File.Exists(file))
                File.Delete(file);
            using (FileStream fileStream = File.OpenWrite(file))
            {
                for (long index = 0; index <= 393216L; ++index)
                {
                    long num = (long) Math.Round(Math.Atan((double) index / 65536.0) * 65536.0);
                    fileStream.Write(BitConverter.GetBytes(num), 0, 8);
                }
                FP fp = FP.FromRaw(393216L);
                long num1 = 4096;
                for (long index = 0; index < 3904L; ++index)
                {
                    fp.RawValue += num1;
                    long num2 = (long) Math.Round(Math.Atan(fp.AsDouble) * 65536.0);
                    fileStream.Write(BitConverter.GetBytes(num2), 0, 8);
                }
                long num3 = 1048576;
                for (long index = 0; index < 609L; ++index)
                {
                    fp.RawValue += num3;
                    long num4 = (long) Math.Round(Math.Atan(fp.AsDouble) * 65536.0);
                    fileStream.Write(BitConverter.GetBytes(num4), 0, 8);
                }
                fileStream.Flush();
            }
        }

        public static void Generate(string directoryPath)
        {
            LutGenerator.GenerateSinCosPacked(Path.Combine(directoryPath, "FPSinCos"));
            LutGenerator.Generate(new Func<double, double>(Math.Tan), Path.Combine(directoryPath, "FPTan"), -205887L, 205887L);
            LutGenerator.Generate(new Func<double, double>(Math.Asin), Path.Combine(directoryPath, "FPAsin"), -65536L, 65536L);
            LutGenerator.Generate(new Func<double, double>(Math.Acos), Path.Combine(directoryPath, "FPAcos"), -65536L, 65536L);
            LutGenerator.GenerateAtan(Path.Combine(directoryPath, "FPAtan"));
            LutGenerator.GenerateSqrt(Path.Combine(directoryPath, "FPSqrt"));
        }
    }
}